﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using NLua;
using Sl.Log;

namespace ChholConfig {
	internal sealed class LuaThread: IDisposable {
		AutoResetEvent BreakLuaStr = new AutoResetEvent(false);

		List<Timer> timer_list = new List<Timer>(1024);
		public void later__(int ms, LuaFunction func, LuaTable table) {
			Task.Run(async () => {
				try {
					await Task.Delay(ms);
					object[] p = new object[table.Values.Count];
					table.Values.CopyTo(p, 0);
					run(lua => func.Call(p));
				}catch(Exception e) {
					Lua_log.LogLine($"【错误】在延迟执行时发生错误:\n{e.Message}");
				}
			});
		}

		public void print__(string s) {
			Lua_log.LogLine($"【脚本】{s}");
		}

		public Logger Lua_log { get; set; }
		string[] lua_reg_func = { "print__", "later__" };
		Thread l_thread;
		public LuaThread(Logger lua_log) {
			Lua_log = lua_log;
			l_thread = new Thread(loopThread) {
				Name = "lua_thread",
				IsBackground = true,
			};
			run(lua => {
				try {
					foreach (string s in lua_reg_func) {
						lua.RegisterFunction(s, this, this.GetType().GetMethod(s));
					}
				} catch (Exception e) {
					Lua_log.LogLine($"【错误】在建立lua基础时发生错误:\n{e.Message}");
				}
			});
			doLua(Properties.Resources.CommonInit);
			l_thread.Start();	
		}
		Queue<Action<Lua>> action_queue = new Queue<Action<Lua>>(256); 
		AutoResetEvent action_enqueue = new AutoResetEvent(false);
		bool thread_exit = false;
		public void doLua(string lua_str) => run(lua => {
			try {
				if (lua.IsExecuting) {
					Console.WriteLine("等待lua执行完成");
					while (lua.IsExecuting) ;
				}
				lua.DoString(lua_str); 
			} catch (System.AccessViolationException e) {
				Console.WriteLine("Lua线程发生了「读写保护内存」异常。");
			} catch (NLua.Exceptions.LuaScriptException e) {
				Lua_log.LogLine($"【错误】{lua_str}无法执行:\n{e.Message}");
			}
		});
		public void run(Action<Lua> action) {
			lock (action_queue) {
				action_queue.Enqueue(action);
			}
			action_enqueue.Set();
		}
		public void loopThread() {
			Lua main_lua = new Lua();
			main_lua.State.Encoding = Encoding.UTF8;
			while (true) {
				if (thread_exit) {
					return;
				}
				Action<Lua> a;
				lock (action_queue) {
					if (action_queue.Count == 0) {
						a = null;
					} else {
						a = action_queue.Dequeue();
					}
				}
				if (a != null) {
					a(main_lua);
				} else {
					action_enqueue.WaitOne();
				}
			}
		}
		public void Dispose() {
			thread_exit = true;
			action_enqueue.Set();
			if (false == l_thread.Join(1000)) {
				l_thread.Abort();
			}
		}
	}
}
